package com.jar.exercise.多线程.Semaphore;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class ThroughputLimiter {

	/**
	 * 接受请求时间窗口
	 */
	private final long[] accessTime;

	/**
	 * 限制数量
	 */
	private final int limit;

	/**
	 * 指向最早请求时间的位置
	 */
	private int curPosition;

	/**
	 * 时间间隔
	 */
	private final long period;

	/**
	 * 限制请求的信号量;
	 */
	private final Semaphore semaphore;


	private final Object LOCK = new Object();

	public ThroughputLimiter(int limit, long period, TimeUnit timeUnit) {
		if (limit < 0) {
			throw new IllegalArgumentException("Illegal Capatity: " + limit);
		}
		this.curPosition = 0;
		this.period = timeUnit.toMillis(period);
		this.limit = limit;
		this.semaphore = new Semaphore(limit);
		this.accessTime = new long[limit];
		Arrays.fill(accessTime, 0);
	}


	public ThroughputLimiter(int limit) {
		// 默认间隔为1S
		this(limit, 1, TimeUnit.SECONDS);
	}

	public void acquire() throws InterruptedException {
//		synchronized (LOCK) {
			semaphore.acquire();
			doAcquire();
//		}
	}

	private void doAcquire() throws InterruptedException {
		long curTime = System.currentTimeMillis();
		if (curTime - accessTime[curPosition] < period) {
			// 未达到处理间隔， 休眠间隔剩余时间
			Thread.sleep(period - (curTime - accessTime[curPosition]) + 1);
			curTime = System.currentTimeMillis();
		}
		accessTime[curPosition++] = curTime;
		curPosition = curPosition % limit;
	}


	public void release() {
		// 任务处理完后释放一个信号量
		semaphore.release();
	}

	public void limit() throws InterruptedException {
//		synchronized (LOCK) {
			doAcquire();
//		}
	}


	public static void main(String[] args) throws InterruptedException {
		ThroughputLimiter throughputLimiter = new ThroughputLimiter(2,3,TimeUnit.SECONDS);
		for (int i = 0; i < 10; i++) {
			throughputLimiter.limit();
			System.out.println(i + " : " + new SimpleDateFormat("HH:mm:ss:SSS").format(new Date()));
		}
		System.out.println(Arrays.toString(throughputLimiter.accessTime));
	}
}
